package com.example.demo.test;

import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;

/**
 * @author: ak
 * @date: 2020/7/12 20:02
 * @description:
 */
public class ProducersAndConsumers {
    static final int CAPACITY = 20;
    static final int PRODUCER_NUMS = 20;
    static final int CONSUMER_NUMS = 25;

    public static void main(String[] args) {

        MessQueue messQueue = new MessQueue(CAPACITY);
        for (int i = 0; i < CONSUMER_NUMS; i++) {
            new Thread(() -> {
                try {
                    messQueue.getMsg();
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }, "消费者" + i).start();
        }

        for (int i = 0; i < PRODUCER_NUMS; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    messQueue.putMsg(new Message(finalI, "食物" + finalI));
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
            }, "生产者" + i).start();
        }
    }
}

@Slf4j
class MessQueue {
    private final LinkedList<Message> queue = new LinkedList<>();
    Integer capacity;

    public MessQueue(Integer capacity) {
        this.capacity = capacity;
    }

    public void putMsg(Message message) throws InterruptedException {
        synchronized (queue) {
            while (queue.size() >= capacity) {
                log.info("食物篮子满了，无法生成食物了，进入等待队列");
                queue.wait();
            }
            queue.addLast(message);
            log.info("{}生产了{}", Thread.currentThread().getName(), message.value);
            queue.notifyAll();
        }
    }

    public Message getMsg() throws InterruptedException {
        synchronized (queue) {
            while (queue.isEmpty()) {
                log.info("食物空了，无法消费，进入等待队列");
                queue.wait();
            }
            queue.notifyAll();
            Message message = queue.removeFirst();
            log.info("{}消费了{}", Thread.currentThread().getName(), message.value);
            return message;

        }
    }

}

class Message {
    Integer id;
    Object value;

    public Message(Integer id, Object value) {
        this.id = id;
        this.value = value;
    }
}
